/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package wifipositioner;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.pi4.locutil.GeoPosition;
import org.pi4.locutil.io.TraceGenerator;
import org.pi4.locutil.trace.Parser;
import org.pi4.locutil.trace.TraceEntry;


public class WifiPositioner {

    private static int K_NUMBER = 3;

    /**
     * @param args the command line arguments
     * @throws java.io.IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO code application logic here

        Parser onlineParser = new Parser(new File("src/data/MU.1.5meters.online.trace"));
        Parser offlineParser = new Parser(new File("src/data/MU.1.5meters.offline.trace"));
        int offlineSize = 25;
        int onlineSize = 5;

        TraceGenerator tg = new TraceGenerator(offlineParser, onlineParser, offlineSize, onlineSize);
        tg.generate();
        List<TraceEntry> offlineTrace = tg.getOffline();
        List<TraceEntry> onlineTrace = tg.getOnline();

        //ArrayList<TraceEntry> offlineEntries = p2.parse();
        //ArrayList<TraceEntry> onlineEntries = p1.parse();
        ModelBasedMapGenerator g = new ModelBasedMapGenerator(-30, -30, 30, 30, 1);
        HashSet<ModelBasedTrace> modelBasedMap = g.Generate(onlineTrace.get(0), 3.415);

        FingerPrintingNN fingerNN = new FingerPrintingNN();
        FingerPrintingKNN fingerKNN = new FingerPrintingKNN(K_NUMBER, false);
        FingerPrintingKNN fingerKNNWeighted = new FingerPrintingKNN(K_NUMBER, true);
        ModelNN modelNN = new ModelNN();
        ModelKNN modelKNN = new ModelKNN(K_NUMBER, false);
        ModelKNN modelKNNWeighted = new ModelKNN(K_NUMBER, true);
        ScoreNN scoreNN = new ScoreNN();
        
//        modelKNNWeighted.CalculatePosition(modelBasedMap, onlineTrace);
        
//        Collection<PositionCalculationResult> results = modelKNN.CalculatePosition(modelBasedMap, onlineTrace);
//        Collection<PositionCalculationResult> distinctResults = distinctAverage(results);
//        
//        double avgDistance = 0;
//        for(PositionCalculationResult r : distinctResults)
//        {
//            System.out.println("Avg. Estimated: " + r.getEstimated().toStringWithoutOrientation() 
//                    + ", True: " + r.getReal().toStringWithoutOrientation()
//                    + ", Error Distance: " + r.getReal().distance(r.getEstimated()) + "m"); 
//            avgDistance += r.getEstimated().distance(r.getReal());
//        }
        
            
        Collection<PositionCalculationResult> results; 
        
//        for (int i = 0; i < 100; i++) {
//            ResultsFile fingerNNFile = new ResultsFile("fingerNN.csv");
//            results = fingerNN.CalculatePositions(offlineTrace, onlineTrace);
//            fingerNNFile.WriteResults(distinctAverage(results));
//            ResultsFile fingerKNNFile = new ResultsFile("fingerKNN.csv");
//            results = fingerKNN.CalculatePositions(offlineTrace, onlineTrace);
//            fingerKNNFile.WriteResults(distinctAverage(results));
//            ResultsFile fingerKNNWeightedFile = new ResultsFile("fingerKNNWeighted.csv");
//            results = fingerKNNWeighted.CalculatePositions(offlineTrace, onlineTrace);
//            fingerKNNWeightedFile.WriteResults(distinctAverage(results));
//            ResultsFile modelNNFile = new ResultsFile("modelNN.csv");
//            results = modelNN.CalculatePosition(modelBasedMap, onlineTrace);
//            modelNNFile.WriteResults(distinctAverage(results));
//            ResultsFile modelKNNFile = new ResultsFile("modelKNN.csv");
//            results = modelKNN.CalculatePosition(modelBasedMap, onlineTrace);
//            modelKNNFile.WriteResults(distinctAverage(results));
//            ResultsFile modelKNNWeightedFile = new ResultsFile("modelKNNWeighted.csv");
            results = modelKNNWeighted.CalculatePosition(modelBasedMap, onlineTrace);
//            modelKNNWeightedFile.WriteResults(distinctAverage(results));

//            //Result file to fingerNN
//            ResultsFile scoreNNFile = new ResultsFile("scoreNN_fingerprintNN.csv");
//            Collection<PositionCalculationResult> fingerNNSamples = fingerNNFile.deserializeFile();            
//            scoreNNFile.WriteResults(scoreNN.CalculateError(fingerNNSamples));            
//            
//           //Result file to fingerKNN 
//            ResultsFile scoreKNNFile = new ResultsFile("scoreNN_fingerprintKNN.csv");
//            Collection<PositionCalculationResult> fingerKNNSamples = fingerKNNFile.deserializeFile();            
//            scoreKNNFile.WriteResults(scoreNN.CalculateError(fingerKNNSamples));
//            
//            //Result file to fingerKNN weighted
//            ResultsFile scoreKNNWeightedFile = new ResultsFile("scoreNN_fingerprintKNNWeighted.csv");
//            Collection<PositionCalculationResult> fingerKNNWeightedSamples = scoreKNNWeightedFile.deserializeFile();            
//            scoreKNNWeightedFile.WriteResults(scoreNN.CalculateError(fingerKNNWeightedSamples));
//            
//            //Result file to modelNN
//            ResultsFile scoreModelNNFile = new ResultsFile("scoreNN_modelNN.csv");
//            Collection<PositionCalculationResult> modelNNSamples = modelNNFile.deserializeFile();            
//            scoreModelNNFile.WriteResults(scoreNN.CalculateError(modelNNSamples));  
//            
//            //Result file to modelKNN
//            ResultsFile scoreModelKNNFile = new ResultsFile("scoreNN_modelKNN.csv");
//            Collection<PositionCalculationResult> modelKNNSamples = modelKNNFile.deserializeFile();            
//            scoreModelKNNFile.WriteResults(scoreNN.CalculateError(modelKNNSamples));
            
            //Result file to modelKNN weighted
//            ResultsFile scoreModelWeightedKNNFile = new ResultsFile("scoreNN_modelKNNWeighted.csv");
//            Collection<PositionCalculationResult> modelKNNWeightedSamples = modelKNNWeightedFile.deserializeFile();            
//            scoreModelWeightedKNNFile.WriteResults(scoreNN.CalculateError(modelKNNWeightedSamples));
//        }

    }
    
    private static Collection<PositionCalculationResult> distinctAverage(Collection<PositionCalculationResult> input)
    {
        HashMap<GeoPosition,Collection<GeoPosition>> truePositionMatrix = new HashMap<>();
        ArrayList<PositionCalculationResult> distinctPosResults = new ArrayList<>();
        
        for(PositionCalculationResult r : input)
        {
            if(!truePositionMatrix.containsKey(r.getReal()))
                truePositionMatrix.put(r.getReal(), new ArrayList<GeoPosition>());
            
            truePositionMatrix.get(r.getReal()).add(r.getEstimated());
        }
        
        for(GeoPosition real : truePositionMatrix.keySet())
        {
            double avgX = 0, avgY = 0;
            
            for(GeoPosition estimated : truePositionMatrix.get(real))
            {
                avgX += estimated.getX();
                avgY += estimated.getY();
            }
            
            avgX /= truePositionMatrix.get(real).size();
            avgY /= truePositionMatrix.get(real).size();
            
            GeoPosition avgPosition = new GeoPosition(avgX, avgY);
            distinctPosResults.add(new PositionCalculationResult(avgPosition, real));
        }
        
        return distinctPosResults;
    }
}
